package data

import (
	"manage/api/class"
	"manage/api/course"
	"manage/api/exam"
	"manage/api/user"
	"manage/internal/biz"
	"time"

	"github.com/Fromsko/gouitls/auth"
	"github.com/dgrijalva/jwt-go"
	"github.com/go-kratos/kratos/v2/log"
	"gorm.io/gorm"
)

type apiRepo struct {
	Data *Data
	log  *log.Helper
}

// NewGreeterRepo .
func NewAPIRepo(Data *Data, logger log.Logger) biz.APIUseRepo {
	repo := &apiRepo{
		Data: Data,
		log:  log.NewHelper(logger),
	}
	repo.setup()
	return repo
}

func (repo *apiRepo) setup() {
	// 自动迁移数据库表
	if err := repo.Data.Mysql.AutoMigrate(&biz.StudentClass{}, &biz.Score{}); err != nil {
		log.Fatal(err)
	}

	/*
		// 查询特定成绩及其关联的考试信息
		var score biz.Score
		result := repo.Data.Mysql.Preload("Exam").First(&score, "exam_id = ?", "fde39fdd0f60")
		if result.Error != nil {
			// 处理查询错误
			fmt.Println(result.Error)
		}

		// 打印成绩及其关联的考试信息
		fmt.Println("Score:", score)
		fmt.Println("Exam:", score.Exam)
	*/
}

func (repo *apiRepo) User(CallBack biz.UserCallBack) {
	CallBack(
		repo.Data.Remote.User.Ctx,
		repo.Data.Remote.User.Fun.(user.UserServiceClient),
	)
}

func (repo *apiRepo) Exam(CallBack biz.ExamCallBack) {
	CallBack(
		repo.Data.Remote.Exam.Ctx,
		repo.Data.Remote.Exam.Fun.(exam.ExamServiceClient),
	)
}

func (repo *apiRepo) Course(CallBack biz.CourseCallBack) {
	CallBack(
		repo.Data.Remote.Course.Ctx,
		repo.Data.Remote.Course.Fun.(course.CourseServiceClient),
	)
}

func (repo *apiRepo) Class(CallBack biz.ClassCallBack) {
	CallBack(
		repo.Data.Remote.Class.Ctx,
		repo.Data.Remote.Class.Fun.(class.ClassServiceClient),
	)
}

func (repo *apiRepo) JoinClass(request *biz.JoinClassRequest) (*biz.JoinClassResponse, error) {
	// 先查询学生班级关联是否存在
	var existingStudentClass biz.StudentClass
	result := repo.Data.Mysql.Where("student_id = ? AND class_id = ?", request.StudentID, request.ClassID).First(&existingStudentClass)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			// 学生班级关联不存在，进行加入操作
			studentClass := biz.StudentClass{
				StudentID: request.StudentID,
				ClassID:   request.ClassID,
				UserName:  request.UserName,
			}
			result := repo.Data.Mysql.Create(&studentClass)
			if result.Error != nil {
				return nil, result.Error
			}

			response := biz.JoinClassResponse{
				Message: "学生加入班级成功",
			}
			return &response, nil
		}
		return nil, result.Error
	}

	response := biz.JoinClassResponse{
		Message: "学生已经加入班级",
	}
	return &response, nil
}

func (repo *apiRepo) LeaveClass(request *biz.LeaveClassRequest) (*biz.LeaveClassResponse, error) {
	var existingStudentClass biz.StudentClass
	result := repo.Data.Mysql.Where("student_id = ? AND class_id = ?", request.StudentID, request.ClassID).First(&existingStudentClass)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			response := biz.LeaveClassResponse{
				Message: "学生已经离开班级",
			}
			return &response, nil
		}
		return nil, result.Error
	}

	result = repo.Data.Mysql.Where("student_id = ? AND class_id = ?", request.StudentID, request.ClassID).Delete(&existingStudentClass)
	if result.Error != nil {
		return nil, result.Error
	}

	response := biz.LeaveClassResponse{
		Message: "学生离开班级成功",
	}
	return &response, nil
}

// GetStudentByClassID 查询学生信息通过ID
func (repo *apiRepo) GetStudentByClassID(classID string) ([]biz.StudentClass, error) {
	var studentClass []biz.StudentClass
	result := repo.Data.Mysql.Where("class_id = ?", classID).Find(&studentClass)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, result.Error
	}
	return studentClass, nil
}

// RemoveStudentsFromClass 将学生从学生班级中移除
func (repo *apiRepo) RemoveStudentsFromClass(classID string) error {
	// 查询班级中的所有学生
	studentClassList, err := repo.GetStudentByClassID(classID)
	if err != nil {
		return err
	}

	// 逐个移除学生
	for _, studentClass := range studentClassList {
		_, err := repo.LeaveClass(&biz.LeaveClassRequest{
			StudentID: studentClass.StudentID,
			ClassID:   studentClass.ClassID,
		})
		if err != nil {
			return err
		}
	}

	return nil
}

type Operat struct {
	*apiRepo
	*auth.SubscriberAuth
}

func (op Operat) GenTokenToRedis(userId string) (string, error) {

	token, err := op.GenToken(userId)
	if err != nil {
		return "", err
	}

	statusCmd := op.Data.RedisCli.Set(
		op.Data.RedisCli.Context(),
		userId, token,
		op.Expiration,
	)
	if statusCmd.Err() != nil {
		return "", err
	}

	return token, nil
}

func (op Operat) CheckTokenInfo(token string) (userId string, _ bool) {

	if valid, _ := op.ValidateToken(token); valid {
		claims, _ := jwt.Parse(token, nil)
		userId := claims.Claims.(jwt.MapClaims)["username"].(string)
		return userId, true
	}
	return "", false
}

func (repo *apiRepo) TokenOperat() biz.Operater {
	return &Operat{
		apiRepo: repo,
		SubscriberAuth: &auth.SubscriberAuth{
			Expiration: time.Minute * time.Duration(repo.Data.Conf.Jwt.Expiration),
			SecretKey:  repo.Data.Conf.Jwt.SecretKey,
		},
	}
}
